using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Sustainalytics.ESG.Entities;

namespace Sustainalytics.ESGRatings.BusinessLogic
{
    public class KeyEsgIssuesRepository : IKeyEsgIssuesRepository
    {
        private IMongoDatabase _clientDwDatabase;

        public KeyEsgIssuesRepository(string clientDw)
        {
            var clientDwConnectionString = MongoUrl.Create(clientDw);

            if (string.IsNullOrWhiteSpace(clientDwConnectionString.DatabaseName))
            {
                throw new ArgumentException("No database specified in the connection string!");
            }

            var clientDwClient = new MongoClient(clientDwConnectionString);
            _clientDwDatabase = clientDwClient.GetDatabase(clientDwConnectionString.DatabaseName);
        }

        public static IKeyEsgIssuesRepository GetInstance(string connectionString)
        {
            return new KeyEsgIssuesRepository(connectionString);
        }

        public void UpdateIndicatorByCompanyIdAndIndicatorNumber(Guid companyId, IList<KeyIndicatorData> datas)
        {
            if (!datas.Any()) return;
            var queryCompany = Builders<CompanyKeyESGIssue>.Filter.Eq(x=> x.Id, companyId);

            var collection = _clientDwDatabase.GetCollection<CompanyKeyESGIssue>(typeof(CompanyKeyESGIssue).Name);

            var col = collection.Find(queryCompany).FirstOrDefault();
            DoUpdateEsgIndicators(datas, col, collection, queryCompany);
        }

        private static void DoUpdateEsgIndicators(
            IList<KeyIndicatorData> datas, 
            CompanyKeyESGIssue col, 
            IMongoCollection<CompanyKeyESGIssue> collection,
            FilterDefinition<CompanyKeyESGIssue> queryCompany)
        {
            try
            {
                int issueIndex;
                int indicatorIndex;
                var willUpdate = false;
                var builder = new List<UpdateDefinition<CompanyKeyESGIssue>>();
                if (col != null)
                {
                    if (col.KeyESGIssues != null)
                    {
                        foreach (var keyIndicatorData in datas)
                        {
                            for (var i = 0; i < col.KeyESGIssues.Count; i++)
                            {
                                var currentKeyEsgIssues = col.KeyESGIssues[i];

                                if (currentKeyEsgIssues != null && currentKeyEsgIssues.KeyEsgIssueIndicators != null)
                                {
                                    for (var j = 0; j < currentKeyEsgIssues.KeyEsgIssueIndicators.Count; j++)
                                    {
                                        var currentIndicator = currentKeyEsgIssues.KeyEsgIssueIndicators[j];
                                        if (currentIndicator != null &&
                                            (currentIndicator.Number == keyIndicatorData.IndicatorNumber ||
                                             currentIndicator.Name == keyIndicatorData.IndicatorNumber))
                                        {
                                            willUpdate = true;
                                            issueIndex = i;
                                            indicatorIndex = j;
                                            builder.Add(Builders<CompanyKeyESGIssue>.Update
                                                   .Set("KeyESGIssues." + issueIndex + ".KeyEsgIssueIndicators." + indicatorIndex +
                                                        ".Score", keyIndicatorData.CompanyScore ?? String.Empty)
                                                   .Set("KeyESGIssues." + issueIndex + ".KeyEsgIssueIndicators." +
                                                        indicatorIndex + ".Average", keyIndicatorData.Average ?? String.Empty)
                                                   .Set("KeyESGIssues." + issueIndex + ".KeyEsgIssueIndicators." +
                                                        indicatorIndex + ".BestPractice", keyIndicatorData.BestPractice ?? String.Empty)
                                                   .Set("KeyESGIssues." + issueIndex + ".KeyEsgIssueIndicators." +
                                                        indicatorIndex + ".MaterialBestPracticeGap",
                                                        keyIndicatorData.MaterialBestPractice)
                                                   .Set("KeyESGIssues." + issueIndex + ".KeyEsgIssueIndicators." +
                                                        indicatorIndex + ".AnswerCategory",
                                                        keyIndicatorData.AnswerCategory ?? String.Empty)
                                                );
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                if (!willUpdate)
                    return;

                collection.UpdateMany(queryCompany, Builders<CompanyKeyESGIssue>.Update.Combine(builder));
            }
            catch (Exception)
            {
                Debug.WriteLine(queryCompany.ToJson());
                throw;
            }
        }

        public CompanyKeyESGIssue GetKeyEsgIssuesByCompanyId(Guid companyId)
        {
            return _clientDwDatabase.GetCollection<CompanyKeyESGIssue>(typeof(CompanyKeyESGIssue).Name).AsQueryable().SingleOrDefault(esg => esg.Id == companyId);
        }

        public List<SubPeerGroupKeyEsgIssue> GetKeyEsgIssuesBySubPeerGroup(int subPeerGroupId)
        {
            return _clientDwDatabase.GetCollection<SubPeerGroupKeyEsgIssue>(typeof(SubPeerGroupKeyEsgIssue).Name)
                .Find(FilterDefinition<SubPeerGroupKeyEsgIssue>.Empty)
                .ToList()
                .Where(kei => kei.SubPeerGroupId == subPeerGroupId)
                .ToList();
        }
    }
}
